/**
 * @author erond
 */

package slave;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import commonUtility.FtpClientThread;


public class SlaveDeleteServerThread extends Thread {

	private ServerSocket deleteSlaveServerSocket_after = null;
	private ServerSocket deleteSlaveServerSocket_before = null;
	private SlaveComunicator sc = null;
	public SlaveDeleteServer_MasterConnectorThread_after slaveDeleteServer_MasterConnectorThread_after = null;
	public SlaveDeleteServer_MasterConnectorThread_before slaveDeleteServer_MasterConnectorThread_before = null;
	private int id = 0;

	/**
	 * Costruttore.
	 * @param sc SlaveComunitcator object
	 */
	public SlaveDeleteServerThread(SlaveComunicator sc) {
		this.sc=sc;
	}	

	public SlaveDeleteServer_MasterConnectorThread_after getDeleteServer_MasterConnectorThread_after() {
		return slaveDeleteServer_MasterConnectorThread_after;
	}

	public SlaveDeleteServer_MasterConnectorThread_before getDeleteServer_MasterConnectorThread_before() {
		return slaveDeleteServer_MasterConnectorThread_before;
	}

	//metodo per lanciare il thread
	public void run() {

		System.out.println("SlaveDeleteServerThread avviato...");

		try {
			deleteSlaveServerSocket_after=new ServerSocket(sc.getSlaveDeleteServerPort_after());
			deleteSlaveServerSocket_after.setReuseAddress(true);
			deleteSlaveServerSocket_before=new ServerSocket(sc.getSlaveDeleteServerPort_before());
			deleteSlaveServerSocket_before.setReuseAddress(true);
		} catch (IOException e3) {
			e3.printStackTrace();
		}

		try { 	

			slaveDeleteServer_MasterConnectorThread_after = new SlaveDeleteServer_MasterConnectorThread_after(id,sc,deleteSlaveServerSocket_after);
			slaveDeleteServer_MasterConnectorThread_after.setName("slaveDeleteServer_MasterConnectorThread_after");
			slaveDeleteServer_MasterConnectorThread_after.start();

			slaveDeleteServer_MasterConnectorThread_before = new SlaveDeleteServer_MasterConnectorThread_before(id,sc,deleteSlaveServerSocket_before);
			slaveDeleteServer_MasterConnectorThread_before.setName("slaveDeleteServer_MasterConnectorThread_before");
			slaveDeleteServer_MasterConnectorThread_before.start();

		} catch(Exception e) {
			System.err.println("SlaveDeleteServerThread: Errore,chiudo...\n");
			e.printStackTrace();
		}

	}//fine run


}//fine SlaveDeleteServerThread


class SlaveDeleteServer_MasterConnectorThread_after extends Thread {

	private ServerSocket deleteSlaveServerSocket_after = null;
	private SlaveComunicator sc = null;
	private int id = 0;
	private Socket masterClientDeleteSocket;

	public SlaveDeleteServer_MasterConnectorThread_after(int id, SlaveComunicator sc, ServerSocket deleteSlaveServerSocket_after) {
		this.deleteSlaveServerSocket_after = deleteSlaveServerSocket_after;
		this.sc=sc;
		this.id=id;
	}

	public SlaveDeleteServer_MasterConnectorThread_after getSlaveDeleteServer_MasterConnectorThread() {
		return this;
	}

	public int getSlaveDeleteServer_MasterConnectorThreadId() {
		return this.id;
	}

	public void run() {

		System.err.println(Thread.currentThread().getName()+": avviato!");

		DataInputStream inSock = null;
		DataOutputStream outSock = null;

		String signal=null;

		try {

			while(true) {

				masterClientDeleteSocket = null;

				/**
				 * la accept() è (s)bloccante!
				 */

				try {
					masterClientDeleteSocket=deleteSlaveServerSocket_after.accept();
					System.err.println(Thread.currentThread().getName()+": sbloccato dalla accept del master.\nSocket creata: "+masterClientDeleteSocket);

					// creazione stream di input e out da socket
					inSock = new DataInputStream(masterClientDeleteSocket.getInputStream());
					outSock = new DataOutputStream(masterClientDeleteSocket.getOutputStream());
				}
				catch (IOException ioe) {
					System.out
					.println("SlaveDeletServer_MasterConnectorThread_after: Problemi nella creazione degli stream di input/output "
							+ "su socket: "+masterClientDeleteSocket);
					ioe.printStackTrace();
					// il server continua l'esecuzione riprendendo dall'inizio del ciclo
					return;
				}

				/**
				 * 1) dobbiamo attendere dal master il file contenente una lista di macaddress
				 *    per i quali interrompere il servizio.
				 * 2) una volta ricevuto il file devo scatenare un evento nei confronti dello SlaveStreamProvider
				 *    per notificargli il fatto che deve andarsi a leggere il file, ed eseguire le interruzioni di servizio.
				 * 3) mi metto in attesa di ricevere un evento scatenato dallo SlaveMaster non appena avrà reso disponibile
				 *    il file 1_transfer_job.xml contenente le varie strutture client,file,mediatime,port da inviare al master
				 * 4) invio il file 1_transfer_job.xml al master. Termino.
				 */


				try {
					while(inSock.available()>=0) {
						signal=inSock.readUTF();
						if(signal.equalsIgnoreCase("AFTERWANTSTHIEFREADY")) {
							System.err.println(Thread.currentThread().getName()+": Ricevuto "+signal+" ..avvio la procedura!");
							/**
							 * se ricevo questa stringa vuol dire che il MASTER ha inviato al mio ftp server
							 * il file after_wants_thief.txt salvandolo come 0_delete.txt
							 * CONTROLLO DI SICUREZZA: invio al vicino la stringa AFTERWANTSTHIEFREADYRECEIVED
							 */
							outSock.writeUTF("AFTERWANTSTHIEFREADYRECEIVED");
							break;
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
					System.exit(1);
				}

				try {
					outSock.flush();
				} catch (IOException ioe) {
					System.err.println(Thread.currentThread().getName()+": Eccezione nella flush");
					ioe.printStackTrace();
				}

				/**
				 * mi sincronizzo con lo slaveManager (perchè potrebbe essere in esecuzione anche il thread
				 * che gestisce le richieste del vicino BEFORE) e sblocco il suo slaveManagerDeleteClientsThread
				 */
				synchronized (sc.sm) {
					sc.sm.setSlaveDeleteServerMasterConnectorThread(Thread.currentThread(), 1);
					System.out.println("DEBUG: "+Thread.currentThread().getName()
							+": lanciata la setDeleteServerMasterConnector con parametri ("
							+Thread.currentThread().getName()+",1");
				}

				synchronized(Thread.currentThread()) {
					try {
						Thread.currentThread().wait();
						//	System.err.println("@@@@@@@@@DEBUG: "+Thread.currentThread().getName()+" sbloccato dalla wait!");
					} catch (InterruptedException e2) {
						e2.printStackTrace();
					}
				}

				/**
				 *    A questo punto posso trasferire il file 1_transfer_job.xml al master, che intanto
				 *    sarebbe dovuto rimanere in attesa di esso.Sul server ftp del master locale il file verrà
				 *    salvato come send_after_transfer_job.xml.
				 */

				FtpClientThread transfer_job_1 = new FtpClientThread(sc.masterJobServerIP, 2121, "./slaveTmp/1_transfer_job.xml", "send_after_transfer_job.xml");
				transfer_job_1.setName("SlaveDeleteServer_MasterConnectorThread_after_transfer_job_1_FtpClient");
				transfer_job_1.start();

				//Attendo che il trasferimento sia completato
				try {
					transfer_job_1.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				while(true) {
					try {
						outSock.writeUTF("TRANSFERJOBONEREADY");
						while(inSock.available()>=0) {
							signal=inSock.readUTF();
							if(signal.equalsIgnoreCase("TRANSFERJOBONEREADYRECEIVED")) {
								//		System.err.println(Thread.currentThread().getName()+": Ricevuto "+signal+" ..continuo!");
								/**
								 * se ricevo questa stringa vuol dire che il master ha ricevuto TRANSFERJOBONEREADY
								 */
								break;
							}
						}
						break;
					} catch (IOException e) {
						e.printStackTrace();
						System.exit(1);
					}
				}

				try {
					outSock.flush();
				} catch (IOException ioe) {
					System.err.println(Thread.currentThread().getName()+": Eccezione nella flush");
					ioe.printStackTrace();
				}

				//		System.err.println("SlaveDeleteServer_MasterConnectorThread_after  FINE CICLO!");

				try {
					System.err.println(Thread.currentThread().getName()+": Avendo finito il ciclo di lavoro, termino la clientSocket di servizio creata da deleteSlaveServerSocket_after.accept()!");
					inSock.close();
					outSock.close();
					masterClientDeleteSocket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
					System.exit(1);
				}

			}//fine while(true)

		} catch (Exception e) {
			System.err.println("SlaveDeleteServer_MasterConnectorThread_after: ECCEZIONE! ..CHIUDO E TERMINO...");
			try {
				masterClientDeleteSocket.close();
			} catch (IOException e1) {
				e1.printStackTrace();
				System.exit(1);
			}
			e.printStackTrace();
			System.exit(1);
		}

	}//fine run()

}//fine SlaveDeleteServer_MasterConnectorThread_after


class SlaveDeleteServer_MasterConnectorThread_before extends Thread {

	private Socket masterClientDeleteSocket;
	private ServerSocket deleteSlaveServerSocket_before = null;
	private SlaveComunicator sc = null;
	private int id = 0;

	public SlaveDeleteServer_MasterConnectorThread_before(int id, SlaveComunicator sc, ServerSocket deleteSlaveServerSocket_before) {
		this.deleteSlaveServerSocket_before = deleteSlaveServerSocket_before;
		this.sc=sc;
		this.id=id;
	}

	public SlaveDeleteServer_MasterConnectorThread_before getSlaveDeleteServer_MasterConnectorThread_before() {
		return this;
	}

	public int getSlaveDeleteServer_MasterConnectorThreadId_before() {
		return this.id;
	}

	public void run() {

		System.err.println(Thread.currentThread().getName()+": avviato!");

		DataInputStream inSock = null;
		DataOutputStream outSock = null;

		String signal=null;

		try {
			while(true) {

				masterClientDeleteSocket = null;

				/**
				 * La accept() è (s)bloccante!
				 */
				try {
					masterClientDeleteSocket=deleteSlaveServerSocket_before.accept();
					System.err.println(Thread.currentThread().getName()+": sbloccato dalla accept del master.\nSocket creata: "+masterClientDeleteSocket);

					// creazione stream di input e out da socket
					inSock = new DataInputStream(masterClientDeleteSocket.getInputStream());
					outSock = new DataOutputStream(masterClientDeleteSocket.getOutputStream());
				}
				catch (IOException ioe) {
					System.out
					.println("SlaveDeletServer_MasterConnectorThread_before: Problemi nella creazione degli stream di input/output "
							+ "su socket: "+masterClientDeleteSocket);
					ioe.printStackTrace();
					// il server continua l'esecuzione riprendendo dall'inizio del ciclo
					return;
				}

				/**
				 * 1) dobbiamo attendere dal master il file contenente una lista di macaddress
				 *    per i quali interrompere il servizio.
				 * 2) una volta ricevuto il file devo scatenare un evento nei confronti dello SlaveStreamProvider
				 *    per notificargli il fatto che deve andarsi a leggere il file, ed eseguire le interruzioni di servizio.
				 * 3) mi metto in wait, in attesa di essere sbloccato dallo SlaveStreamProvider non appena avrà reso disponibile
				 *    il file 0_transfer_job.xml contenente le varie strutture client,file,transmittedtime,port da inviare al master
				 * 4) invio il file 0_ransfer_job.xml al master. Termino il ciclo.
				 */


				try {
					while(inSock.available()>=0) {
						signal=inSock.readUTF();
						if(signal.equalsIgnoreCase("BEFOREWANTSTHIEFREADY")) {
							System.err.println(Thread.currentThread().getName()+": Ricevuto "+signal+" ..avvio la procedura!");
							/**
							 * se ricevo questa stringa vuol dire che il MASTER ha inviato al mio ftp server
							 * il file before_wants_thief.txt salvandolo come 0_delete.txt
							 * CONTROLLO DI SICUREZZA: invio al vicino la stringa BEFOREWANTSTHIEFREADYRECEIVED
							 */
							outSock.writeUTF("BEFOREWANTSTHIEFREADYRECEIVED");
							break;
						}
					}
				} catch (IOException e) {
					e.printStackTrace();
					System.exit(1);
				}

				try {
					outSock.flush();
				} catch (IOException ioe) {
					System.err.println(Thread.currentThread().getName()+": Eccezione nella flush");
					ioe.printStackTrace();
				}

				/**
				 * mi sincronizzo con lo slaveManager (perchè potrebbe essere in esecuzione anche il thread
				 * che gestisce le richieste del vicino AFTER) e sblocco il suo slaveManagerDeleteClientsThread
				 */
				synchronized (sc.sm) {
					sc.sm.setSlaveDeleteServerMasterConnectorThread(Thread.currentThread(), 0);
					System.out.println("DEBUG: "+Thread.currentThread().getName()
							+": lanciata la setDeleteServerMasterConnector con parametri ("
							+Thread.currentThread().getName()+",0");
				}

				//		System.err.println(Thread.currentThread().getName()+" si mette wait dallo stato: "+Thread.currentThread().getState().toString());

				synchronized(Thread.currentThread()) {
					try {
						Thread.currentThread().wait();
						//		System.err.println("@@@@@@@@@DEBUG: "+Thread.currentThread().getName()+" sbloccato dalla wait!");
					} catch (InterruptedException e2) {
						e2.printStackTrace();
					}
				}

				/**
				 *    A questo punto posso trasferire il file 0_transfer_job.xml al master locale, che intanto
				 *    sarebbe dovuto rimanere in attesa di esso. Sul server ftp del master locale il file verrà
				 *    salvato come send_before_transfer_job.xml.
				 */

				FtpClientThread transfer_job_0 = new FtpClientThread(sc.masterJobServerIP, 2121, "./slaveTmp/0_transfer_job.xml", "send_before_transfer_job.xml");
				transfer_job_0.setName("SlaveDeleteServer_MasterConnectorThread_before_transfer_job_0_FtpClient");
				transfer_job_0.start();

				//Attendo che il trasferimento sia completato
				try {
					transfer_job_0.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

				while(true) {
					try {
						outSock.writeUTF("TRANSFERJOBZEROREADY");
						while(inSock.available()>=0) {
							signal=inSock.readUTF();
							if(signal.equalsIgnoreCase("TRANSFERJOBZEROREADYRECEIVED")) {
								System.err.println(Thread.currentThread().getName()+": Ricevuto "+signal+" ..continuo!");
								/**
								 * se ricevo questa stringa vuol dire che il master ha ricevuto TRANSFERJOBZEROREADY
								 */
								break;
							}
						}
						break;
					} catch (IOException e) {
						e.printStackTrace();
						System.exit(1);
					}
				}

				try {
					outSock.flush();
				} catch (IOException ioe) {
					System.err.println(Thread.currentThread().getName()+": Eccezione nella flush");
					ioe.printStackTrace();
				}

				//		System.out.println(Thread.currentThread().getName()+": FINE CICLO!");

				try {
					System.err.println(Thread.currentThread().getName()+": Avendo finito il ciclo di lavoro, termino la clientSocket di servizio creata da deleteSlaveServerSocket_before.accept()!");
					inSock.close();
					outSock.close();
					masterClientDeleteSocket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
					System.exit(1);
				}

			}//fine while(true)

		} catch (Exception e) {
			System.err.println("SlaveDeleteServer_MasterConnectorThread_before: ECCEZIONE! ..CHIUDO E TERMINO...");
			try {
				inSock.close();
				outSock.close();
				masterClientDeleteSocket.close();
			} catch (IOException e1) {
				e1.printStackTrace();
				System.exit(1);
			}
			e.printStackTrace();
			System.exit(1);
		}

	}//fine run()

}//fine SlaveDeleteServer_MasterConnectorThread_before